{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to Survival Support Vector Machine\n",
    "\n",
    "This guide demonstrates how to use the efficient implementation of *Survival Support Vector Machines*, which is an extension of the standard [Support Vector Machine](https://en.wikipedia.org/wiki/Support_vector_machine) to right-censored time-to-event data. Its main advantage is that it can account for complex, non-linear relationships between features and survival via the so-called kernel trick. A kernel function implicitly maps the input features into high-dimensional feature spaces where survival can be described by a hyperplane. This makes Survival Support Vector Machines extremely versatile and applicable to a wide a range of data. A popular example for such a kernel function is the [Radial Basis Function](https://en.wikipedia.org/wiki/Radial_basis_function_kernel).\n",
    "\n",
    "Survival analysis in the context of Support Vector Machines can be described in two different ways:\n",
    "\n",
    "1. As a **ranking** problem: the model learns to assign samples with shorter survival times a lower *rank* by considering all possible pairs of samples in the training data.\n",
    "2. As a **regression** problem: the model learns to directly predict the (log) survival time.\n",
    "\n",
    "In both cases, the disadvantage is that predictions cannot be easily related to standard quantities in survival analysis, namely survival function and cumulative hazard function. Moreover, they have to retain a copy of the training data to do predictions.\n",
    "\n",
    "Let's start by taking a closer look at the Linear Survival Support Vector Machine, which does not allow selecting a specific kernel function, but can be fitted faster than the more generic Kernel Survival Support Vector Machine.\n",
    "\n",
    "\n",
    "## Linear Survival Support Vector Machine\n",
    "\n",
    "The class [sksurv.svm.FastSurvivalSVM](https://scikit-survival.readthedocs.io/en/latest/api/generated/sksurv.svm.FastSurvivalSVM.html#sksurv.svm.FastSurvivalSVM) is used to train\n",
    "a linear Survival Support Vector Machine. Training data consists of $n$ triplets $(\\mathbf{x}_i, y_i, \\delta_i)$, where\n",
    "$\\mathbf{x}_i$ is a $d$-dimensional feature vector, $y_i > 0$ the survival time or time of censoring, and $\\delta_i \\in \\{0,1\\}$ the binary event indicator. Using the training data, the objective is to minimize the following function:\n",
    "\n",
    "\\begin{equation}\n",
    "\\arg \\min_{\\mathbf{w}, b} \\frac{1}{2} \\mathbf{w}^T \\mathbf{w}+ \\frac{\\alpha}{2} \\left[\n",
    "r \\sum_{i,j \\in \\mathcal{P}}\n",
    "\\max(0, 1 - (\\mathbf{w}^T \\mathbf{x}_i - \\mathbf{w}^T \\mathbf{x}_j))^2\n",
    "+ (1 - r) \\sum_{i=0}^n \\left( \\zeta_{\\mathbf{w},b} (y_i, x_i, \\delta_i) \\right)^2\n",
    "\\right]\n",
    "\\end{equation}\n",
    "\n",
    "\\begin{equation}\n",
    "\\zeta_{\\mathbf{w},b} (y_i, \\mathbf{x}_i, \\delta_i) =\n",
    "\\begin{cases}\n",
    "\\max(0, y_i - \\mathbf{w}^T \\mathbf{x}_i - b) & \\text{if $\\delta_i = 0$,}\\\\\n",
    "y_i - \\mathbf{w}^T \\mathbf{x}_i - b & \\text{if $\\delta_i = 1$,}\\\\\n",
    "\\end{cases}\n",
    "\\end{equation}\n",
    "\n",
    "\\begin{equation}\n",
    "\\mathcal{P} = \\{ (i, j)~|~y_i > y_j \\land \\delta_j = 1 \\}_{i,j=1,\\dots,n}\n",
    "\\end{equation}\n",
    "\n",
    "The hyper-parameter $\\alpha > 0$ determines the amount of regularization to apply: a smaller value increases the amount of regularization and a higher value reduces the amount of regularization. The hyper-parameter $r \\in [0; 1]$ determines the trade-off between the ranking objective and the regression objective. If $r = 1$ it reduces to the ranking objective, and if $r = 0$ to the regression objective.\n",
    "\n",
    "The class [sksurv.svm.FastSurvivalSVM](https://scikit-survival.readthedocs.io/en/latest/api/generated/sksurv.svm.FastSurvivalSVM.html#sksurv.svm.FastSurvivalSVM) adheres to interfaces used in [scikit-learn](https://scikit-learn.org) and thus it is possible to combine it with auxiliary classes and functions from scikit-learn. In this example, we are going to use the ranking objective ($r = 1$) and [GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html) to determine the best setting for the hyper-parameter $\\alpha$ on the Veteran's Lung Cancer data. \n",
    "\n",
    "First, we have to import the classes we are going to use."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas\n",
    "import seaborn as sns\n",
    "from sklearn import set_config\n",
    "from sklearn.model_selection import ShuffleSplit, GridSearchCV\n",
    "\n",
    "from sksurv.datasets import load_veterans_lung_cancer\n",
    "from sksurv.column import encode_categorical\n",
    "from sksurv.metrics import concordance_index_censored\n",
    "from sksurv.svm import FastSurvivalSVM\n",
    "\n",
    "set_config(display=\"text\")  # displays text representation of estimators\n",
    "sns.set_style(\"whitegrid\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we load data of the *Veteran's Administration Lung Cancer Trial* from disk and convert it to numeric values. The data consists of 137 patients and 6 features. The primary outcome measure is death (`Status`, `Survival_in_days`).\n",
    "The original data can be retrieved from http://lib.stat.cmu.edu/datasets/veteran."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_x, y = load_veterans_lung_cancer()\n",
    "x = encode_categorical(data_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`data_x` is a data frame containing the features, and `y` is a structured array containing the event indicator $\\delta_i$, as boolean, and the survival/censoring time $y_i$ for training.\n",
    "\n",
    "Now, we are essentially ready to start training, but before let's determine what the amount of censoring for this data is and plot the survival/censoring times."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6.6% of records are censored\n"
     ]
    }
   ],
   "source": [
    "n_censored = y.shape[0] - y[\"Status\"].sum()\n",
    "print(f\"{n_censored / y.shape[0] * 100:.1f}% of records are censored\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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ffp09enTR5JUXl6upKQkSVJycrL27dvn3xUCAICQ0eRNyIqLi9WzZ0898MAD2rRpk6TPb6HqcrkkSdHR0bp69WqzL+L1elVRUWGw3Ju19eYq/lpXR+TxeJhXADHvwGHWgcW8AycYs24yLF599VW5XC7t379fFRUVyszM1KVLlxo+X1NTo9jY2GZfJDIyst3eya69rqs94o6EgcW8A4dZBxbzDhx/zvpWwdJkWGzfvr3hz2lpacrJydHatWtVVlamMWPGqLS0VPfdd5/tSgEAQMhq8emmmZmZys/P17Rp0+Tz+ZSSkuKPdQEAgBDU5BGLLyssLGz4c1FRkV8WAwAAQhsXyAIAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGbczT2hrq5O2dnZ+uCDDxQeHq5Vq1bJcRxlZWXJ5XJp8ODBWr58ucLCaBQAADq7ZsNiz549kqQdO3aorKysISwyMjI0ZswYLVu2TCUlJXrooYf8vlgAANC+NXuY4cEHH1Rubq4k6aOPPlJcXJzKy8uVlJQkSUpOTta+ffv8u0oAABASmj1iIUlut1uZmZl64403tH79eu3Zs0cul0uSFB0dratXrza5vdfrVUVFRdtX24ihQ4e2aXt/rasj8ng8zCuAmHfgMOvAYt6BE4xZ31ZYSNKaNWu0aNEi/fCHP5TX6214vKamRrGxsU1uGxkZ2eYA8Jf2uq72qKKignkFEPMOHGYdWMw7cPw561sFS7NvhfzhD3/QCy+8IEm644475HK5NHz4cJWVlUmSSktLlZiYaLhU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\n",
      "text/plain": [
       "<Figure size 648x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(9, 6))\n",
    "val, bins, patches = plt.hist(\n",
    "    (y[\"Survival_in_days\"][y[\"Status\"]], y[\"Survival_in_days\"][~y[\"Status\"]]), bins=30, stacked=True\n",
    ")\n",
    "_ = plt.legend(patches, [\"Time of Death\", \"Time of Censoring\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we need to create an initial model with default parameters that is subsequently used in the grid search."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "estimator = FastSurvivalSVM(max_iter=1000, tol=1e-5, random_state=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we define a function for evaluating the performance of models during grid search. We use Harrell's concordance index."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def score_survival_model(model, X, y):\n",
    "    prediction = model.predict(X)\n",
    "    result = concordance_index_censored(y[\"Status\"], y[\"Survival_in_days\"], prediction)\n",
    "    return result[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The last part of the setup specifies the set of parameters we want to try and how many repetitions of training and testing we want to perform for each parameter setting. In the end, the parameters that on average performed best across all test sets (100 in this case) are selected. [GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html) can leverage multiple cores by evaluating multiple parameter settings concurrently (4 jobs in this example)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "param_grid = {\"alpha\": 2.0 ** np.arange(-12, 13, 2)}\n",
    "cv = ShuffleSplit(n_splits=100, test_size=0.5, random_state=0)\n",
    "gcv = GridSearchCV(estimator, param_grid, scoring=score_survival_model, n_jobs=1, refit=False, cv=cv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, start the hyper-parameter search. This can take a while since a total of ``13 * 100 = 1300`` fits have to be evaluated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import warnings\n",
    "\n",
    "warnings.filterwarnings(\"ignore\", category=UserWarning)\n",
    "gcv = gcv.fit(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check what is the best average performance across 100 random train/test splits we got and the corresponding hyper-parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.72, {'alpha': 0.00390625})"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "round(gcv.best_score_, 3), gcv.best_params_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we retrieve all 100 test scores for each parameter setting and visualize their distribution by box plots."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_performance(gcv):\n",
    "    n_splits = gcv.cv.n_splits\n",
    "    cv_scores = {\"alpha\": [], \"test_score\": [], \"split\": []}\n",
    "    order = []\n",
    "    for i, params in enumerate(gcv.cv_results_[\"params\"]):\n",
    "        name = f'{params[\"alpha\"]:.5f}'\n",
    "        order.append(name)\n",
    "        for j in range(n_splits):\n",
    "            vs = gcv.cv_results_[f\"split{j}_test_score\"][i]\n",
    "            cv_scores[\"alpha\"].append(name)\n",
    "            cv_scores[\"test_score\"].append(vs)\n",
    "            cv_scores[\"split\"].append(j)\n",
    "    df = pandas.DataFrame.from_dict(cv_scores)\n",
    "    _, ax = plt.subplots(figsize=(11, 6))\n",
    "    sns.boxplot(x=\"alpha\", y=\"test_score\", data=df, order=order, ax=ax)\n",
    "    _, xtext = plt.xticks()\n",
    "    for t in xtext:\n",
    "        t.set_rotation(\"vertical\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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6tWrl+677z6r4zVqy5YtmjJlitxutyIiIlRZWSnDMDRp0iQlJydbHa9Vq66u1sKFC/XPf/5TFRUVnu/XW2+9VW3btvVrFsqmpL59+yo8PFxt27aVYRg6cOCAOnbsqKCgIH3wwQdWx/Pqd7/7nQYNGiSn06mXXnpJL730kmJjY3X33XfrjTfesDpeo7Kzs4/72hNPPOHHJE2Xnp6uvLw8uVwu3X///crOztYVV1yhzMxMzZs3z+p4jbrzzjs1ePBgXXnllZ5fXh999JEWL16sV1991ep4jbJzdsnehc3un71dS9uIESO0YMGCBs8ZhqFhw4Zp8eLFFqXyzfDhw/Xkk0/q9NNP9zz37bff6t577w347FJgFbamGjt2rM4999wG369r1qzR5s2b/X5AhNPokhYtWqTHHntMY8eOVY8ePWxRFn6qpqZGQ4cOlSS99dZb6tGjhyQpNDTw//dee+21euqpp5STk2N1lCZr06aNunTpIkl64YUX9Lvf/U7x8fEKCgqyOJl3TqdT1113nedxVFSUfvOb32j+/PkWpvKNnbNL0gMPPKDBgwfr3nvvbVDYsrOzA76w2f2z/+STT44qbZmZmRo2bFhAl02Xy6VvvvlGZ511lue5b775RsHBgT/swuVyNSiaknT66afb4uekJE2YMEHnnnuu7rvvvgaFLTs7O+DPYP33v//Vk08+2eC5c889VyNGjPB7lsBvI37QtWtXPfHEE5o0aZL69etnm2+CeqeccopmzJghp9Opmpoavfnmm4qKilJERITV0bxKTU3Vv/71L5WVlWnQoEFWx2mSyMhIvf7660pPT1d8fLxmzJih++6776jLMgJRXFycZs2apSuvvFJRUVGewhMfH291NK/snF2yd2Gz+2dv19L24IMP6q677lJtba2ioqLkdDoVFhamRx55xOpoXl111VW6/fbbdfnll6tdu3aeo8lXXnml1dF8EkiFranCw8P19ttvKyUlRe3atZPT6dSaNWss6QacRv+ZmTNnavny5Xr//fetjuIzp9Opv/3tb0pKSlJ0dLRmz56tDh066J577tGpp55qdbxWy+l06pVXXtFvf/tbRUVFSZK++OILPfnkk3r22WctTte4+lNDGzdu9JzKTU5OVnp6esCfGvpp9srKSkVFRemiiy7S8OHDAz67JN1zzz1KSko6qrDt2rVLTz/9tNXxGmX3z76wsFA5OTnHLG2Bft2mVPczp7KyUpGRkZ6fOXawffv2o/aZ8847z+pYPhk1apRuuOGGowrbO++8o7lz51odr1EOh0OzZ8/Wv//9b89+k5ycrKysLL9fskPZ/NHOnTsVHh6uhIQEz3ObN2/WhRdeaGEq31VXV6u4uFhVVVWKiYlRUlKSbY7Q2jm7w+FQTEyMSktLVVRUpG7duqlbt25Wx/LK6XR6flkVFxdrx44dOv/889W1a1eLk/mmtrZWO3bskNPpVPv27dW9e3dbDOaT7F/Y7PzZ17Nbaau/zvfn1w3a4TpfqW5Q1ieffKKKigp16NDBFoOy6gVSYTtR5eXlnu9Xq2YCoGxKmj17ttauXSuXy6VevXp5Tk2MHDlSr7/+usXpvPvwww/1zDPPKCEhQZs2bdKFF16ovXv36s9//rNnhHSgsnP2KVOm6Mwzz1RcXJxee+019e3bV5s3b9bAgQM1atQoq+M1qn7fXrJkiRYuXKhLLrlEGzdu1E033aS0tDSr4zXqww8/1BNPPKFzzjnHM7r1yy+/1NixY3XNNddYHc8ndi1sdv/s7Vra7Dwwy66Dsn4uEApbU/10JoDIyEg5nU7rZgIwYAwbNsxwu92GYRhGfn6+MXnyZMMwDOPWW2+1MJXvbr31VqO6utowDMMoLy83HnjgAaOiosIYPny4xcm8s3P2tLQ0wzAMY8SIEUZlZaVhGIZRW1tr3HzzzVbG8klmZqZhGIaRnp5uOJ1OwzAMo6amxkhPT7cylk/S0tKMioqKBs8dOnTIFp+7YRjG6tWrjeuvv9646667jPvvv98YM2aMMWjQIGPlypVWR/PK7p/9HXfcYbz77rtGRUWF4Xa7jYqKCuOdd94xbrvtNqujNWrEiBHHfN4OPyePldHtdhtDhgyxIE3Tbd682bjllluMm266ybj11luN//u//zMGDx5sbNy40epoXqWnpxvffvttg+f27NljyWfPACHVTSFRf9p2/Pjxys7O1ty5c21zKreiosKTNTw8XLt371ZUVJQtBqrYObthGDp48KA6d+6sH374QREREZ6/HANdZWWlDh48qPj4eM+sBaGhoaqtrbU4mXe1tbVHnW4ODw+3zffrnDlztHDhwganbysqKnT77bcH/NFBu3/2dh2cZeeBWXYdlFUvLy9PM2fOtOXUTYE0EwBlU9J1112nIUOGaO7cuYqOjlZeXp6ysrK0efNmq6P55LrrrtPQoUN18cUXa8OGDRoxYoRefPFF9erVy+poXtk5++jRo5WZmamkpCTdeOON+sUvfqFdu3Zp7NixVkfz6qKLLtLo0aNVWlqqV155RZmZmRoxYoRuvPFGq6N5lZaWpptuukl9+vTxXLC/ceNGZWZmWh3NJ3YubHb/7O1a2h5//HEtXLhQL774YoPrfB999FGro3ll55H0UmAVtqYKpJkAuGbzR//5z390xhlnKCQkxPNcQUFBwB9pqLdz506VlJSoR48eSkxMVHl5uWJjY62O5ZP67ElJSeratatn0I0dVFZWatOmTZ7MvXr1ss3nLtUdna2qqtIpp5yir776yjYDhA4cOKAtW7Z4fvH+4he/UMeOHa2O5ZM333xT8+bNO2Zhq58vN5DZ+bO38+Asu17nW89ug7LqzZo1Sxs2bDiqsPXp00d33XWX1fG8CpSZACibPyooKDjqFmbXXnutLf56keryf/LJJ54fRHbJbxiGPvjgA3Xs2FFdunRRXl6egoODNXbs2ID/BfaPf/xDgwYNUmVlpWbNmqUdO3bovPPOU1ZWliIjI62O16jy8nK9+OKLCgsL0+233+4p97NmzbLFD1C77u/17FzY7P7Z27G02Xlgll0HZf1UoBS2ExEoMwFQNiU98sgjcrvdR93SyeVyafr06VbH88rO+adMmaLDhw9r//79OnjwoNLS0hQZGally5Zpzpw5VsdrVP2I7okTJ+qss85SamqqPv30U23atCngb7X5+9//XqmpqXK5XFqwYIFeeOEFnXnmmbaYgcHO+3s9uxY2u3/2di1t6enpmjt37jGv812yZImFybyz80j6eoFS2JoqkGYC4JpNSbt27dJf//rXBs9dffXVSk9PtyhR09g5/44dO7RgwQLV1NTohhtu8JxGXLRokcXJfPf1119r2rRpkuruRmWHGwLU1NR4pjjq2bOnRo8erXnz5tlicJOd93fp+IVt7dq1AV/Y7P7Z23Vwlp2v87XroKx6Py1snTt39pzJssPUTYF0e1bKpiS3260NGzY0mNdx/fr1atOmjYWpfGf3/Bs3blSfPn30yiuvSJJKS0ttMRr966+/1quvvqrQ0FBt375dvXr10ueff26L7EeOHFFxcbF69Oih5ORk3XnnncrKylJVVZXV0byy+/5u58Jm98/e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4he/0K5duzR27Fhdd911VsfzqqSkRI899pjGjh2rHj162Opo/vTp03XkyBF16tTJczr9o48+ktvtVm5url+zUDYBACeF8vJyPf744/r3v/+tPXv2KDo6Wn369NH48eN1xhlnWB3vuJYsWaLvvvtO/fv319ixYz1TNU2ePFmXXXaZ1fG8qqys1KZNmzwDhXr16qXY2FirY/nM6XRq0qRJ6tevn9566y1bXJ8s1c3WsXTpUq1du1YOh8Ozvw8dOtTvlwBQNgEACGC33HKL5s2bp6ysLOXk5KhLly7at2+fRo8erSVLllgdr1H/+Mc/NGjQIFVWVmrWrFnasWOHzjvvPGVlZSkyMtLqeE0yc+ZMLV++XO+//77VUXxWXV2tHTt26PDhw4qJiVFSUhK3qwQAwCzHGpxVL5AHZ7Vp00YRERGKjIxU586dJUmdOnWyxWUjCxcu1KBBg5SXl6ezzjpLEydO1KeffqpJkybZZpDTzp07FR4errvvvlt33323JGnz5s1HDVQMNB9++KGeeeYZJSQkqLCwUBdccIH27t2rP//5zw3uVe8PlE0AwEnBroOzBgwYoKysLCUlJenOO+9USkqKPv74Y/3qV7+yOprPvv76a02bNk2S1LVrV9scHZw9e7bWrl0rl8ulXr166ZFHHpEkPfHEEwF/Ov2ll17SG2+8obCwMDkcDj322GN66aWXdMcdd2jBggV+zcIdhAAAJ4ULL7xQgwcPVnFxsc4888wG/wSyO+64Q7/97W9lGIbOOOMMlZWVKTMzU+PGjbM6mldff/21Xn31VYWEhGj79u2SpM8///yoKYUC1Zo1a7RgwQItXrxYERERysnJkSRbjKavqKjwHP0ODw/X7t27FRUVZclnz5FNAMBJ4/e//73VEU7IxRdfrIsvvtjqGE02Z84cbd++XYmJiSouLlbnzp01depU29wBqX4OXKluntbs7GzNnTvXFpcwXHfddRo6dKguvvhibdiwQSNGjNCLL76oXr16+T0LA4QAAIApVq1apalTpyo0NFT33XeffvOb30iquxNYoJ+GlqRXX31V77zzjubOnavo6GjV1NQoKytLGzZs0ObNm62O59XOnTtVUlKiHj16KDExUeXl5ZbMBMCRTQAAYIo5c+bo73//uwzD0L333quamhrddNNNtjgNLdXdR/zqq6/23M40LCxML730kgoKCixO5pvdu3dr/fr1Wr16tdq3b68+ffro2muv9fuRWcomAAAwRZs2bRQdHS1JevbZZ3Xbbbfp9NNPt8Vp6HrFxcV69dVXVVFR0aCwBbpHHnlEbrdbV155pSIjI1VZWak1a9Zo7dq1mj59ul+zcBodAACY4v7771dMTIzuvfdeRURE6LvvvtOoUaN06NAhrV271up4Xh2vsLlcLr8Xtqa69dZbj3mHr/T0dL9P9cWRTQAAYIrc3FwtW7bMcyTz9NNP1+uvv67nn3/e4mS+2bVr11GF7eqrr1Z6erpFiXzndru1YcOGBnNqrl+/Xm3atPF7Fo5sAgAAHMOIESM0duzYowrbM888E/D3SN+9e7fy8vK0fft2ud1uORwOpaSkaPz48TrnnHP8moWyCQAAcAz1hW3btm0yDEPBwcHq1auXJYWtqb766itJ/5sTdPz48XrsscckSV26dPFrFsomAABAK9OvXz+1bdtWp556qgzDUHFxsc4991xJ8vu0U5RNAACAY8jMzFRtbe0xX/P3IJumKisr0+TJkzV8+HBdfvnlyszMtOzUP2UTAADgGDZv3qyJEydq9uzZCgkJafBaoN/mVJJcLpceffRRxcXFad26dZaVTe6NDgAAcAwXXnihBg8erOLiYp155pkN/rGD0NBQPfTQQ55T6VbhyCYAAABMw5FNAAAAmIayCQAAANNQNgHADzIzM1VSUnLc1y+//HI/pgEA/6FsAgAAwDTcGx0AWpjT6dRDDz2kiooKORwODR061PPazJkz9eWXX6qsrEyHDh3SxIkT1bdvX9XU1Cg7O1vffvutoqOj9cwzz6isrEw5OTmqrq7WwYMHNWbMGF1zzTUWfmUA0HSUTQBoYaWlpfrNb36jX//619q3b58yMzPVqVMnz+tt27bV66+/rl27dik7O1vLli1TVVWV/vSnP+mss85SZmamioqK5HQ69dvf/laXXHKJ/v3vf2vmzJmUTQC2Q9kEgBbWsWNHvfbaa3r//fcVFRUll8vV4PVf/epXkqTu3bvrwIEDkqQOHTrorLPO8rz/8OHDio+P13PPPae33npLQUFBR60HAOyAazYBoIW9/PLL6t27t2bMmKFrr732qMmUt23bJknauXOn54hnUFDQUet5+umnNXjwYD3++OO65JJLLJ2UGQBOFEc2AaCF9e/fXzk5OVq+fLmio6MVEhKimpoaz+tFRUW67bbbdPjwYU2dOvW467n22ms1ffp0Pf/88zr99NPlcDj8ER8AWhR3EAIAP5o5c6Y6duyo4cOHWx0FAPyC0+gAAAAwDUc2AQAAYBqObAIAAMA0lE0AAACYhrIJAAAA01A2AQAAYBrKJgAAAEzz/wEmQqE3NFf2hAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 792x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_performance(gcv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can observe that the model seems to be relative robust with respect to the choice for $\\alpha$ for this dataset. Let's fit a model using the $\\alpha$ value that performed best."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "FastSurvivalSVM(alpha=0.00390625, max_iter=1000, optimizer='avltree',\n",
       "                random_state=0, tol=1e-05)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "estimator.set_params(**gcv.best_params_)\n",
    "estimator.fit(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is important to remember that only if the ranking objective is used exclusively ($r = 1$),\n",
    "that predictions denote risk scores, i.e. a higher predicted value indicates shorter survival,\n",
    "a lower value longer survival."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-1.59  -1.687]\n",
      "[( True,  72.) ( True, 411.)]\n"
     ]
    }
   ],
   "source": [
    "pred = estimator.predict(x.iloc[:2])\n",
    "print(np.round(pred, 3))\n",
    "print(y[:2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The model predicted that the first sample has a lower risk than the second sample, which is in concordance with the actual survival times."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Regression Objective\n",
    "\n",
    "If the regression objective is used ($r < 1$), the semantics are different, because now predictions are on the time scale and lower predicted values indicate shorter survival, higher values longer survival.\n",
    "Moreover, we saw from the histogram of observed times above that the distribution is skewed, therefore\n",
    "the survival/censoring times will be log-transformed by the `FastSurvivalSVM` internally, when using a $r < 1$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's fit a model using the regression objective ($r = 0$) and compare its performance to the ranking model from above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.736\n"
     ]
    }
   ],
   "source": [
    "ref_estimator = FastSurvivalSVM(rank_ratio=0.0, max_iter=1000, tol=1e-5, random_state=0)\n",
    "ref_estimator.fit(x, y)\n",
    "\n",
    "cindex = concordance_index_censored(\n",
    "    y[\"Status\"],\n",
    "    y[\"Survival_in_days\"],\n",
    "    -ref_estimator.predict(x),  # flip sign to obtain risk scores\n",
    ")\n",
    "print(round(cindex[0], 3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that `concordance_index_censored` expects risk scores, therefore, we had to flip the sign of predictions.\n",
    "The resulting performance of the regression model is comparable to the of the ranking model above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[120.786 149.963]\n"
     ]
    }
   ],
   "source": [
    "pred = ref_estimator.predict(x.iloc[:2])\n",
    "print(np.round(pred, 3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Kernel Survival Support Vector Machine\n",
    "\n",
    "The *Kernel Survival Support Vector Machine* is a generalization of the *Linear Survival Support Vector Machine* that can account for more complex relationships between features and survival time, it is implemented in [sksurv.svm.FastKernelSurvivalSVM](https://scikit-survival.readthedocs.io/en/latest/api/generated/sksurv.svm.FastKernelSurvivalSVM.html#sksurv.svm.FastKernelSurvivalSVM). The disadvantage is that the choice of kernel function and its hyper-parameters is often not straightforward and requires tuning to obtain good results. For instance, the [Radial Basis Function](https://en.wikipedia.org/wiki/Radial_basis_function_kernel) has a hyper-parameter $\\gamma$ that needs to be set: $k(x, x^\\prime) = \\exp(-\\gamma \\|x-x^\\prime \\|^2)$. There are many other [built-in kernel functions](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.pairwise_kernels.html#sklearn.metrics.pairwise.pairwise_kernels) that can be used by passing their name as `kernel` parameter to `FastKernelSurvivalSVM`.\n",
    "\n",
    "In this example, we are going to use the clinical kernel, because it is able to distinguish between continuous, ordinal, and nominal attributes. As this is a custom kernel function, we first need to pre-compute the kernel matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sksurv.kernels import clinical_kernel\n",
    "from sksurv.svm import FastKernelSurvivalSVM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "kernel_matrix = clinical_kernel(data_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As with the *Linear Survival Support Vector Machine* above, we are going to determine the optimal $\\alpha$ value  by using [GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "kssvm = FastKernelSurvivalSVM(optimizer=\"rbtree\", kernel=\"precomputed\", random_state=0)\n",
    "\n",
    "kgcv = GridSearchCV(kssvm, param_grid, scoring=score_survival_model, n_jobs=1, refit=False, cv=cv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that when using a custom kernel, we do not pass the original data (`data_x`) to the fit function, but the pre-computed, square kernel matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "kgcv = kgcv.fit(kernel_matrix, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, print the best average concordance index and the corresponding parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.709, {'alpha': 0.015625})"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "round(kgcv.best_score_, 3), kgcv.best_params_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we visualize the distribution of test scores obtained via cross-validation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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0G/dFEw7AVA2JXXu3FljxoxR79693ScEfPjhh+rcubPV0bxi5/x2zn7hhRdq4MCB2r59u1JTU62Oc1L69eunrKwspaSk6N5771Xv3r31z3/+U5deeqnV0TyqqKjQLbfcourqai1cuFA33nijpkyZcsyRcsHKzoXNzt+vkn1L25QpU5SXl6fs7Ox683yfeuopq6N5ZOeV9FJwFbaTFUw7ATBnU0dPsSksLDxmtVxqaqotfvuyc347Z7e7f//731q7dq0cDodiY2PVs2dP9enTx+pYXqmtrVVxcbGaN2+us88+W4sXL9agQYMUHh78vz+PHz9etbW1xxQ2O5wXbffv18awOMtu83wl+y7KkqSHHnpIKSkpxxS2nTt36oUXXrA6XoOCaScAyuZPysrK9Nlnn7lPCOjevbvOOOMMq2N5zc757Z593bp17mNO7Zb9s88+cy+UsFP21atXKzIyst5ipsLCQlssOLB7YbPz9+vP2am02X1hlh0XZdUJpsJ2KoJlJwDKpqSFCxdqwYIF6tWrl3u13Lp163Tbbbdp6NChVsfzyM75G0P2nj17uufyfPbZZxo0aJBtstvxeZ8wYYIqKirkdDp16NAhzZgxQxEREbY4arOOXQubnV83kn1L2+23337ceb5TpkwJ+nm+dl5JXydYCtvJCqqdAAK+JCkIDRkyxKitra33vpqaGtuslrNzfrJbw87Z09PT3f/95ptvGllZWYZhHN0dwA7efvtt49ZbbzXy8vKMF154wcjNzTVuueUWY968eVZH88jOrxvDsO9q+hPlC/bchmHvlfSGYRirV682rr/+euOBBx4wHn30UeP+++83BgwYYKxYscLqaB4F004AwT/BKQCcTqdqamrqTRL/8ccfbTHEL9k7P9mtYefsR44cUW1trSIiIpSZmalvv/3WfTa9HSxevFjz58+v99zX1tZq6NChQT86aOfXjWTfxVl2Xphl10VZdWbPnq358+fX21uzoqJCd955Z9BP2wmmnQAom5JGjhypW265RUlJSe7VcqWlpRozZozV0bxi5/xkt4ads99+++26/vrr9dZbbyk+Pl6PPvqonnjiCa1fv97qaF6xc2Gz8+tGsm9pmzBhgnueb2VlpWJiYtS3b19b7ILx85X0khQaGqouXbrYYiW9FFyF7WQF004AzNn8idPpVElJifsbOTk52RYrW+vYOT/ZrWHn7DU1NYqIiKj3A3/btm3q2rWrham8s2rVKk2ZMuW4hc0OuwHY+XVj/GxxVl3+Hj162GZx1i/t2bNHZ555ptUxGrW3335bc+fOPW5hGzRokNXxPKrbCaDu9X7BBRdYshMAZbMBCxcutMWL6UTsnJ/s1iB7YNi5sB2PnZ7747FraRs9erSefvppq2OckokTJ2rcuHFWx/BKsBQ2f1m9erX69u0b0K8ZGtCvZgM/P4XktNNOszDJqbFzfrJbg+yBFx4ers6dO6tnz57q3LmzwsPDtXDhQqtjnbSysjJJ9nruj+f555+3OsIpsWvRlKSMjAyrI3itVatW6tevn2688Ub169dPrVq10urVq62OdcpKS0sD/jXt+6u0H9Vth7FlyxaFh4fX2w7DDuycn+zWIHvwsUNh++qrr+q9XTeydt5551mUyD/sVtry8vJs9Xp3OByKi4tTaWmpioqK1KlTJ3Xq1MnqWD6xorD5y5133hnwr8ltdNl7DzPJ3vnJbg2y41T06dNHzZs31xlnnCHDMFRcXKxzzz1XISEhttjj9Ouvv9aXX36pSy65RC+99JK2bt2qTp066b777lOLFi2sjndCPz+73TAMlZSUuMtasL/mJ06cqLZt2yohIUFvvPGGevXqpU2bNiktLU0jRoywOl6j9uGHH6q0tFR9+/bVmDFjtGvXLp111lmaOHGizj333IBmYWRT9t0Oo46d85PdGmS3TmZmpg4fPlzvfYZhKCQkJOiLw+LFizV+/HgNHTpUl19+uTIzMzV37lyrY3lt9OjRevjhhzV58mSdeeaZeuSRR/TZZ58pJydHL730ktXxTigjI0OLFy/W448/rtNOO005OTmaNm2a1bG8sm3bNo0bN04ZGRnKz89XVFSUnE6nhgwZYouyWVtbW+/tESNG6NVXX5VhGEG/sfv06dM1c+ZMjRs3Tg8//LB+/etfq7i4WOPHj9eCBQsCmoWyKftuh1HHzvnJbg2yW2fUqFEaO3asZs6caZvjEuskJCToT3/6k55++ml9/vnnVsc5aWFhYbrkkks0e/Zs99Y7Xbp00T/+8Q+LkzXshhtuUKdOnfTMM89ozJgxioyMVNu2ba2O5RXDMHTgwAG1b99eP/74o6KiolRZWSm73FT9zW9+o8jISDVv3lyGYWj//v1KS0tTSEiIVq5caXW8BkVERKh169aSpF//+teSFPARzTrcRpf9t8Owc36yW4Ps1pozZ46SkpJssU/iifztb3/T3/72N/31r3+1OorXRo4cqRtvvFF79uxRbGys+vbtqw8//FDvvPOOXn31VavjeXTgwAE99thjKi0t1dKlS62O45UPP/xQU6dOVUpKij799FOdf/752rlzp7Kzs3XttddaHc+jkpISPfPMM8rOzlbnzp1tNZo/efJkHTlyRK1bt3bfTv/www/lcrmUm5sb0CyUTQBAk1BeXq5nn31W//nPf/TNN98oNjZWPXv21OjRo3XWWWdZHe+EFi9erO+++059+/ZVdna2e6um8ePH6ze/+Y3V8TyqqqrShg0b3AuFunbtqvj4eKtjea2yslLjxo1Tnz59tGjRIlvMT5aO7tbx7rvvau3atXI4HO7X+6BBgwI+BYCyCQBAELv11ls1d+5cZWVlacKECerQoYP27t2rkSNHavHixVbHa9A//vEPDRgwQFVVVZoxY4aKi4t13nnnKSsrS9HR0VbHOynTp0/XkiVLtHz5cqujeK2mpkbFxcU6dOiQ4uLilJKSwnGVAACY5XiLs+oE8+KsZs2aKSoqStHR0Wrfvr0kqXXr1raYNjJ//nwNGDBAeXl5ateuncaOHatPPvlE48aNs80ipx07digyMlIPPvigHnzwQUnSpk2bjlmoGGw++OADvfjii0pKStLGjRt1wQUXaM+ePfrDH/5Q76z6QKBsAgCaBLsuzurXr5+ysrKUkpKie++9V71799Y///lPXXrppVZH89quXbs0adIkSVJycrJtRgdnzpyptWvXyul0qmvXrnryySclSdOmTQv62+mvvPKK3nrrLUVERMjhcOiZZ57RK6+8onvuuUfz5s0LaBZOEAIANAkXXnihBg4cqO3bt6tt27b1/glm99xzj373u9/JMAydddZZKisrU2ZmpkaNGmV1NI927dql119/XWFhYdq2bZsk6fPPPz9mS6FgtWbNGs2bN08LFy5UVFSUJkyYIEm2WE1fUVHhHv2OjIzU7t27FRMTY8lzz8gmAKDJ+P3vf291hFNy8cUX6+KLL7Y6xkmbPXu2tm3bpo4dO2r79u1q3769nnrqKducgFS3B650dJ/WnJwczZkzxxZTGK699loNGjRIF198sdatW6dhw4bp5ZdfVteuXQOehQVCAADAFKtWrdJTTz2l8PBwPfLII7ruuuskHT0JLNhvQ0vS66+/rvfff19z5sxRbGysamtrlZWVpXXr1mnTpk1Wx/Nox44dKikpUefOndWxY0eVl5dbshMAI5sAAMAUs2fP1t///ncZhqGHH35YtbW1uvnmm21xG1o6eo54//793ceZRkRE6JVXXlFhYaHFybyze/duffbZZ1q9erVOP/109ezZU9dcc03AR2YpmwAAwBTNmjVTbGysJOnPf/6z7rjjDrVp08YWt6HrbN++Xa+//roqKirqFbZg9+STT8rlcumKK65QdHS0qqqqtGbNGq1du1aTJ08OaBZuowMAAFM8+uijiouL08MPP6yoqCh99913GjFihA4ePKi1a9daHc+jExU2p9MZ8MJ2soYPH37cE77S09MDvtUXI5sAAMAUubm5eu+999wjmW3atNGbb76pv/zlLxYn887OnTuPKWz9+/dXenq6RYm853K5tG7dunp7an722Wdq1qxZwLMwsgkAAHAcw4YNU3Z29jGF7cUXXwz6M9J3796tvLw8bdu2TS6XSw6HQ71799bo0aN19tlnBzQLZRMAAOA46grb1q1bZRiGQkND1bVrV0sK28n66quvJP1vT9DRo0frmWeekSR16NAhoFkomwAAAI1Mnz591Lx5c51xxhkyDEPbt2/XueeeK0kB33aKsgkAAHAcmZmZOnz48HE/FuhFNierrKxM48eP19ChQ3X55ZcrMzPTslv/lE0AAIDj2LRpk8aOHauZM2cqLCys3seC/ZhTSXI6nXr66aeVkJCgjz76yLKyydnoAAAAx3HhhRdq4MCB2r59u9q2bVvvHzsIDw/X448/7r6VbhVGNgEAAGAaRjYBAABgGsomAAAATEPZBIAAyMzMVElJyQk/fvnllwcwDQAEDmUTAAAApuFsdADws8rKSj3++OOqqKiQw+HQoEGD3B+bPn26vvzyS5WVlengwYMaO3asevXqpdraWuXk5Ojbb79VbGysXnzxRZWVlWnChAmqqanRgQMHdP/99+uqq66y8E8GACePsgkAflZaWqrrrrtOV199tfbu3avMzEy1bt3a/fHmzZvrzTff1M6dO5WTk6P33ntP1dXV+n//7/+pXbt2yszMVFFRkSorK/W73/1Ol1xyif7zn/9o+vTplE0AtkPZBAA/a9Wqld544w0tX75cMTExcjqd9T5+6aWXSpLOOecc7d+/X5LUsmVLtWvXzv35hw4dUmJiombNmqVFixYpJCTkmOsAgB0wZxMA/OzVV19V9+7dNXXqVF1zzTXHbKa8detWSdKOHTvcI54hISHHXOeFF17QwIED9eyzz+qSSy6xdFNmADhVjGwCgJ/17dtXEyZM0JIlSxQbG6uwsDDV1ta6P15UVKQ77rhDhw4d0lNPPXXC61xzzTWaPHmy/vKXv6hNmzZyOByBiA8AfsUJQgAQQNOnT1erVq00dOhQq6MAQEBwGx0AAACmYWQTAAAApmFkEwAAAKahbAIAAMA0lE0AAACYhrIJAAAA01A2AQAAYJr/D0dbG+p6hEQfAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 792x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_performance(kgcv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can see that the choice of $\\alpha$ is much more important here, compared to the Linear Survival Support Vector Machine. Nevertheless, the best performance is below that of the linear model, which illustrates that choosing a good kernel function is essential, but also a non-trivial task."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "> Pölsterl, S., Navab, N., and Katouzian, A.,\n",
    "> *Fast Training of Support Vector Machines for Survival Analysis*,\n",
    "> Machine Learning and Knowledge Discovery in Databases: European Conference,\n",
    "> ECML PKDD 2015, Porto, Portugal,\n",
    "> Lecture Notes in Computer Science, vol. 9285, pp. 243-259 (2015)\n",
    "\n",
    "> Pölsterl, S., Navab, N., and Katouzian, A.,\n",
    "> *An Efficient Training Algorithm for Kernel Survival Support Vector Machines*\n",
    "> 4th Workshop on Machine Learning in Life Sciences,\n",
    "> 23 September 2016, Riva del Garda, Italy"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
